﻿using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace KunURP
{
    public class ScanLine : ScriptableRendererFeature
    {
        public enum Axis
        {
            X,
            Y,
            Z,
        }

        [System.Serializable]
        public class Setting
        {
            public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;//默认插到透明完成后
            public Material material;
            public Axis axis;
        }

        public Setting m_Setting = new Setting();

        class CustomRenderPass : ScriptableRenderPass
        {
            public const int MaxLevel = 16;

            public Material material;
            public Axis axis;

            FilterMode passFilterMode{ get;set;}//图像的模式
            RenderTargetIdentifier passSource{get;set;}//源图像,目标图像
            string passTag;

            static class ShaderIDs
            {
                internal static readonly int Matrix = Shader.PropertyToID("_Matrix");
                internal static readonly int SourceTex = Shader.PropertyToID("_SourceTex");
            }

            public CustomRenderPass(string tag)
            {
                this.passTag = tag;
            }

            public void Setup(RenderTargetIdentifier passSource)
            {
                this.passSource = passSource;
                if (axis == Axis.X)
                {
                    this.material.DisableKeyword("_AXIS_Y");
                    this.material.DisableKeyword("_AXIS_Z");
                    this.material.EnableKeyword("_AXIS_X");
                }
                else if (axis == Axis.Y)
                {
                    this.material.DisableKeyword("_AXIS_X");
                    this.material.DisableKeyword("_AXIS_Z");
                    this.material.EnableKeyword("_AXIS_Y");
                }
                else if (axis == Axis.Z)
                {
                    this.material.DisableKeyword("_AXIS_X");
                    this.material.DisableKeyword("_AXIS_Y");
                    this.material.EnableKeyword("_AXIS_Z");
                }
            }
            
            public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
            {
                CommandBuffer cmd = CommandBufferPool.Get(this.passTag);
                RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
                Camera camera = renderingData.cameraData.camera;
                float halfHeight = camera.nearClipPlane * Mathf.Tan(Mathf.Deg2Rad * camera.fieldOfView * 0.5f);
                Vector3 toTop = camera.transform.up * halfHeight;
                Vector3 toRight = camera.transform.right * halfHeight * camera.aspect;
                Vector3 forward = camera.transform.forward * camera.nearClipPlane;
                Vector3 topLeft = forward + toTop - toRight;
                Vector3 topRight = forward + toTop + toRight;
                Vector3 bottomLeft = forward - toTop - toRight;
                Vector3 bottomRight = forward - toTop + toRight;
                float scale = topLeft.magnitude / camera.nearClipPlane;
                topLeft.Normalize();
                topLeft *= scale;
                topRight.Normalize();
                topRight *= scale;
                bottomLeft.Normalize();
                bottomLeft *= scale;
                bottomRight.Normalize();
                bottomRight *= scale;
                Matrix4x4 matrix = new Matrix4x4();
                matrix.SetRow(0, bottomLeft);
                matrix.SetRow(1, bottomRight);
                matrix.SetRow(2, topRight);
                matrix.SetRow(3, topLeft);
                material.SetMatrix(ShaderIDs.Matrix, matrix);
                cmd.GetTemporaryRT(ShaderIDs.SourceTex, opaqueDesc);
                cmd.CopyTexture(this.passSource, ShaderIDs.SourceTex);
                cmd.Blit(ShaderIDs.SourceTex, this.passSource, material);
                cmd.ReleaseTemporaryRT(ShaderIDs.SourceTex);
                context.ExecuteCommandBuffer(cmd);
                CommandBufferPool.Release(cmd);
            }

        }

        CustomRenderPass m_ScriptablePass;

        public override void Create()
        {
            this.m_ScriptablePass = new CustomRenderPass(name);
            this.m_ScriptablePass.renderPassEvent = this.m_Setting.passEvent;
            this.m_ScriptablePass.material = this.m_Setting.material;
            this.m_ScriptablePass.axis = this.m_Setting.axis;
        }

        // Here you can inject one or multiple render passes in the renderer.
        // This method is called when setting up the renderer once per-camera.
        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            if (this.m_Setting.material != null)
            {
                this.m_ScriptablePass.Setup(renderer.cameraColorTarget);
                renderer.EnqueuePass(this.m_ScriptablePass);
            }
        }
    }
}